from solidMass import SolidMass
from pointMass import PointMass
from spring import Spring
from vec3 import Vec3

import math

class Sphere(SolidMass):
    def __init__(self, r = 1, pos = Vec3(), mass = 1, stiffness = 1, slices = 5, stacks = 5):
        SolidMass.__init__(self)

        stacks -= 2
        stackPoints = []
        for i in range(stacks):
            th = float(i+1) / float(stacks+1) * math.pi
            stackPoints.append([])
            for j in range(slices):
                ph = float(j) / float(slices) * math.pi * 2
                x = r * math.sin(th) * math.cos(ph)
                y = r * math.cos(th)
                z = r * math.sin(th) * math.sin(ph)
                stackPoints[-1].append(PointMass(Vec3(x,y,z)+pos,mass))
            self.pointMasses.extend(stackPoints[-1])

        center = PointMass(pos,mass)
        top = PointMass(pos + Vec3(0,r,0),mass)
        bottom = PointMass(pos + Vec3(0,-r,0),mass)
        self.pointMasses.extend([center,top,bottom])

        for i in range(stacks):
            for j in range(slices):
                nextj = (j+1) % slices
                self.springs.append(Spring(stackPoints[i][j],stackPoints[i][nextj]))

                self.springs.append(Spring(stackPoints[i][j],center))

                if i < stacks - 1:
                    self.springs.append(Spring(stackPoints[i][j],stackPoints[i+1][j]))
                    self.springs.append(Spring(stackPoints[i][j],stackPoints[i+1][nextj]))
                    self.springs.append(Spring(stackPoints[i+1][j],stackPoints[i][nextj]))

        for i in range(slices):
            self.springs.append(Spring(stackPoints[-1][i],bottom))
            self.springs.append(Spring(stackPoints[0][i],top))
        self.springs.append(Spring(center,top))
        self.springs.append(Spring(bottom,center))

        for spring in self.springs:
            spring.stiffness = stiffness

        for pm in self.pointMasses:
            pm.mass = mass / float(len(self.pointMasses))
            
    def updateCollision(self):
        self.collisionCenter = self.getCenter()
        self.collisionRadius = self.getBoundingRadius()
            
    def testCollision(self, pm):
        return (pm.pos - self.collisionCenter).length() < self.collisionRadius

    def reactCollision(self, pm):
        pm.pos = self.collisionCenter + (pm.pos - self.collisionCenter).norm() * (self.collisionRadius + 0.1)
